import os
import time

from Extend.GrandClass import GrandClass
from Extend.Log import LogMethod
from Extend.NoSql import NoSqlDataGet
import gevent
from Extend.LocalError import LocalSqlServerError
import shutil
from Extend.NoSql import Heart


class TargetServer:
    def __init__(self, server, paths: list):
        self.server = server
        self.path = []
        self.addPath(paths)

    def addPath(self, paths):
        for path in paths:
            if ':' not in path:
                path = os.path.join(r"\\" + self.server, path)
            self.path.append(path)

    def changePath(self, paths: list):
        self.path = paths


class FileToFile:

    # 获取订单服务器下所有文件
    @staticmethod
    def getAllFile(files_path):
        target_files = []
        for path, directory, files in os.walk(files_path):
            for file in files:
                target_files.append(os.path.join(path, file))
        return target_files

    # 复制单个文件
    @staticmethod
    def copyFile(source_file, target_file):
        folder = os.path.dirname(target_file)
        if not os.path.exists(folder):
            os.makedirs(folder)
        shutil.copyfile(source_file, target_file)

    @staticmethod
    def copyAllFile(source_folder, target_folder):
        # 具体的形式 shutil.copytree('\\\\172.16.200.252\\Imorder\\2020.21.28', 'D:/Imorder/2020.21.28')
        # 如果目标存在会报错，所以先删除
        if os.path.exists(target_folder):
            shutil.rmtree(target_folder)
        shutil.copytree(source_folder, target_folder)


class FileControl(GrandClass):
    def __init__(self, local_server: dict, target_server_list: list):
        super().__init__()
        self.local_server = self.__addDataServer(local_server)
        self.recovery_server = []
        self.target_servers = []
        self.__addServer(target_server_list)

    @staticmethod
    def __addDataServer(server_dict):
        server = server_dict['Server']
        path = server_dict['FilePath']
        file_server = TargetServer(server, path)
        return file_server

    def __addServer(self, server_list: list):
        for x in server_list:
            self.target_servers.append(self.__addDataServer(x))

    def _recoveryServer(self, server):
        for x in self.target_servers + self.recovery_server:
            if x is server:
                return
        self.recovery_server.append(server)

    def recoveryServerToRun(self):
        while self.recovery_server:
            server = self.recovery_server.pop()
            self.target_servers.append(server)
            LogMethod.addLog([10, "服务器:%s 已经恢复文件读取" % server.server, ""])

    def addServer(self, server_list: list):
        self.clearServeList()
        self.__addServer(server_list)

    # 循环主逻辑
    def startMonitors(self):
        while Heart.getMeHeart(self.__class__.__name__, ):
            super().startMonitors()
            if len(self.recovery_server) > 0:
                self.recoveryServerToRun()
                continue
            for x in NoSqlDataGet.GetNeed('S', 'F'):
                for y in self.target_servers:
                    if x["Server"] == y.server:
                        this_server = y
                        break
                else:
                    continue
                try:
                    # st = time.time()
                    for t_path, l_path in zip(this_server.path, self.local_server.path):
                        source_path = os.path.join(t_path, x['OrderNO'])
                        files = FileToFile.getAllFile(source_path)
                        for file in files:
                            FileToFile.copyFile(file, file.replace(t_path, l_path))
                    NoSqlDataGet.AppendSuccess('F', x)
                    # print('复制孔位文件等耗时%.2f秒' % (time.time() - st))
                except Exception as err:
                    try:
                        self.removeServer(this_server, err)
                    except LocalSqlServerError as error:
                        LogMethod.addLog([11, "本地文件异常", str(error)])
                        Heart.setMeStat(self.__class__.__name__, False)
                        Heart.setMeHeart(self.__class__.__name__, False)
                        return
                    except Exception as error:
                        LogMethod.addLog([12, "未知异常，具体错误请查询详情", str(error)])
            gevent.sleep(1)  # 工作太快协程会不检测服务器状态
        Heart.setMeStat(self.__class__.__name__, False)
        # print('结束关闭')

    def removeServer(self, server, error):
        if server is self.local_server:
            raise LocalSqlServerError(error)
        for i in range(len(self.target_servers)):
            if self.target_servers[i] is server:
                self.target_servers.pop(i)
                break
        LogMethod.addLog([13, "服务器:%s 复制文件到本地失败" % server.server, str(error)])
        gevent.spawn(MonitorServer.heartbeatDetection, server, "PROADMIN", self._recoveryServer)

    def clearServeList(self):
        for i in range(len(self.target_servers)):
            server = self.target_servers.pop(i)
            del server


class MonitorServer:
    @staticmethod
    def heartbeatDetection(obj: TargetServer, path, return_func, loop=0):
        while True:
            try:
                if os.path.isdir(path):
                    for x, y, z in os.walk(path):
                        pass
                    else:
                        break
                else:
                    raise IOError
            except Exception as e:
                loop += 1
                if loop <= 50:
                    time.sleep(5)
                elif loop <= 100:
                    time.sleep(10)
                else:
                    time.sleep(20)
        return_func(obj)

if __name__ == '__main__':
    dc = FileControl(
        {'Server': '172.16.200.147',
         'FilePath': ['D:\\IMOS\\Imorder', 'D:\\IMOS\\product\ROVER', 'D:\\IMOS\\product\CNC']},
        [{'Server': '172.16.200.21', 'FilePath': ['Imorder', 'product\ROVER', 'product\CNC']},
         {'Server': '172.16.200.252', 'FilePath': ['Imorder', 'product\ROVER', 'product\CNC']}])
    dc.start()
